//
//  menu.c
//  PongNorris Project
//
//  Created by -- on 11/12/12.
//
//  This code use Winbgim library, get it here : http://winbgim.codecutter.org

#include "menu.h"
#include "gfx.h"
#include "game.h"

#define MENU_ITEM_HEIGHT    20
#define MENU_REGISTER_MAX    8

#define MENU_DEFAULT_X  30
#define MENU_DEFAULT_Y  120
#define MENU_DEFAULT_WIDTH  120

static Menu *_menu_register[MENU_REGISTER_MAX];

void menu_init(void)
{
    memset(_menu_register, 0, sizeof(_menu_register));
}

void menu_exit(void) {}

void menu_initialize(Menu *menu, const char *items[])
{
    // Set up default position
    menu->x = MENU_DEFAULT_X;
    menu->y = MENU_DEFAULT_Y;
    menu->width = MENU_DEFAULT_WIDTH;

    menu->active_item = 0;

    // Fill in the items' caption
    int i;
    for(i = 0; items[i] != 0; i++)
    {
        strcpy(menu->items[i].caption, items[i]);
        menu->items[i].offset = 0;
    }
    menu->nb_items = i;

    menu_clear_enabled(menu);
}

void menu_draw(Menu *menu)
{
    // Draw each item
    float xoff = menu->x, yoff = menu->y;

    for(int i = 0; i < menu->nb_items; i++)
    {
        // Draw solid background color
        if(menu->active_item == i)
        {
            gfx_custom_color(32, 128, 0);
            gfx_draw_set_bkcolor(GFX_GREEN);

            menu->items[i].offset += 1;
            if(menu->items[i].offset >= 10)
            {
                menu->items[i].offset = 10;
            }
        }
        else
        {
            if(menu->items[i].enabled)
            {
                gfx_draw_set_color(GFX_BLUE);
                gfx_draw_set_bkcolor(GFX_BLUE);
            }
            else
            {
                gfx_draw_set_color(GFX_BLACK);
                gfx_draw_set_bkcolor(GFX_BLACK);
            }

            menu->items[i].offset -= 1;
            if(menu->items[i].offset < 0)
            {
                menu->items[i].offset = 0;
            }
        }
        xoff += menu->items[i].offset;
        // Translate all drawing to the menu item coordinates
        mat3 m_translate;
        vec2 v_tranlate = { xoff, yoff };
        mat3_identity(m_translate);
        mat3_translate(m_translate, v_tranlate);

        gfx_matrix_push(m_translate);

        gfx_draw_rectangle(0, 0, menu->width+4, MENU_ITEM_HEIGHT);

        // Draw lines around items
        gfx_draw_set_color(GFX_WHITE);
        gfx_draw_line(0,                0,                   menu->width+4,    0);
        gfx_draw_line(menu->width+4,  0,                   menu->width+4,    MENU_ITEM_HEIGHT);
        gfx_draw_line(menu->width+4,  MENU_ITEM_HEIGHT,    0,                  MENU_ITEM_HEIGHT);
        gfx_draw_line(0,                MENU_ITEM_HEIGHT,    0,                  0);

        // Draw text
        gfx_draw_set_color(GFX_WHITE);
        gfx_draw_text(4, 2, menu->items[i].caption);

        gfx_draw_set_bkcolor(GFX_BLACK);

        gfx_matrix_pop();
        yoff += MENU_ITEM_HEIGHT;

        xoff -= menu->items[i].offset;
    }
}

void menu_draw_all()
{
    gfx_set_blur(.75);
    menu_draw_virtual_background();
    gfx_draw_image("data/menu.bmp", (640.-500)/2, 10);
    for(int i = 0; i < MENU_REGISTER_MAX; i++)
    {
        if(_menu_register[i] != 0)
        {
            menu_draw(_menu_register[i]);
        }
    }
}

void menu_draw_register(Menu *menu)
{
    for(int i = 0; i < MENU_REGISTER_MAX; i++)
    {
        if(_menu_register[i] == 0)
        {
            _menu_register[i] = menu;
            return;
        }
    }
    puts("ERR:Too many menus to register!");
    exit(EXIT_FAILURE);
}

void menu_draw_unregister(Menu *menu)
{
    for(int i = 0; i < MENU_REGISTER_MAX; i++)
    {
        if(_menu_register[i] == menu)
        {
            _menu_register[i] = 0;
        }
    }
}

MenuAction menu_input_tick(Menu *menu)
{
    int buttons = io_player_get_buttons_menu();

    if(buttons & IO_PLAYER_TOP)
    {
        menu->active_item--;

        // Prevent the active item from leaving the top
        if(menu->active_item < 0)
        {
            menu->active_item = 0;
        }
        else
        {
            sfx_sound_play(SFX_SOUND_MENU_CHANGE);
        }
    }
    else if(buttons & IO_PLAYER_BOTTOM)
    {
        menu->active_item++;

        // Prevent the active item from leaving the bottom
        if(menu->active_item >= menu->nb_items)
        {
            menu->active_item = menu->nb_items - 1;
        }
        else
        {
            sfx_sound_play(SFX_SOUND_MENU_CHANGE);
        }
    }
    else if(buttons & IO_PLAYER_CROSS)
    {
        sfx_sound_play(SFX_SOUND_MENU_ENTER);
        return MENU_ACTION_ENTER;
    }
    else if(buttons & IO_PLAYER_PAUSE || buttons & IO_PLAYER_CIRCLE)
    {
        return MENU_ACTION_RETURN;
    }
    return MENU_ACTION_NONE;
}

void menu_main(void)
{
    Menu m;
    const char *captions[] = {"New Game", "Level Editor", "Options", "Highscores", "Quit", 0} ;
    menu_initialize(&m, captions);
    menu_draw_register(&m);

    while(1)
    {
        // Check user input
        MenuAction action = menu_input_tick(&m);

        // Act if prompted
        if(action == MENU_ACTION_ENTER)
        {
            switch(m.active_item)
            {
                case 0: { menu_new_game(); break; }
                case 1:
                {
                    menu_draw_unregister(&m);
                    editeur_start();
                    menu_draw_register(&m);

                    // Read input buttons to prevent quitting
                    io_player_get_buttons_menu();
                    break;
                }
                case 2: { menu_options(); break; }
                case 3:
                {
                    menu_highscores();
                    break;
                }

                case 4: goto end;
            }
        }
        else if(action == MENU_ACTION_RETURN) { goto end; }

        // Render everything
        gfx_scene_begin();
        menu_draw_all();
        gfx_scene_end();
    }

    end:
    menu_draw_unregister(&m);
    return;
}

void menu_new_game(void)
{
    Menu m;
    const char *captions[] = {"1 Player", "2 Players", "3 Players", "4 Players", "Back", 0} ;
    menu_initialize(&m, captions);
    m.x = MENU_DEFAULT_WIDTH + MENU_DEFAULT_X*2;
    menu_draw_register(&m);

    int nb_players = -1;

    while(1)
    {
        // Check user input
        MenuAction action = menu_input_tick(&m);

        // Act if prompted
        if(action == MENU_ACTION_ENTER)
        {
            switch(m.active_item)
            {
                case 0: { nb_players = 1; break; }
                case 1: { nb_players = 2; break; }
                case 2: { nb_players = 3; break; }
                case 3: { nb_players = 4; break; }

                case 4: goto end;
            }
        }
        else if(action == MENU_ACTION_RETURN) { goto end; }

        if(nb_players != -1)
        {
            menu_draw_unregister(&m);
            game_set_nb_of_players(nb_players);
            game_set_level(1);
            game_init();
            game_mainloop();
            return;
        }

        // Render everything
        gfx_scene_begin();
        menu_draw_all();
        gfx_scene_end();
    }

    end:
    menu_draw_unregister(&m);

    return;
}

void menu_options(void)
{
    Menu m;
    const char *captions[] = {"Resolution", "Multisampling", "Sound", "Back", 0} ;
    menu_initialize(&m, captions);
    m.x = MENU_DEFAULT_WIDTH + MENU_DEFAULT_X*2;
    menu_draw_register(&m);

    while(1)
    {
        // Check user input
        MenuAction action = menu_input_tick(&m);

        // Act if prompted
        if(action == MENU_ACTION_ENTER)
        {
            switch(m.active_item)
            {
                case 0: { menu_options_resolution(); break; }
                case 1: { menu_options_multisampling(); break; }
                case 2: { menu_options_sound(); break; }
                case 3: goto end;
            }
        }
        else if(action == MENU_ACTION_RETURN) { goto end; }

        // Render everything
        gfx_scene_begin();
        menu_draw_all();
        gfx_scene_end();
    }

    end:
    menu_draw_unregister(&m);

    return;
}

void menu_options_resolution(void)
{
    Menu m;
    const char *captions[] = {"640x360", "1280x720", "1920x1080", "Back", 0} ;
    menu_initialize(&m, captions);
    m.x = MENU_DEFAULT_WIDTH*2 + MENU_DEFAULT_X*3;
    menu_draw_register(&m);

    // Get current resolution
    GFX_Resolution res;
    gfx_get_resolution(&res);
    switch(res.width)
    {
        case 640:  { m.active_item = 0; break; }
        case 1280: { m.active_item = 1; break; }
        case 1920: { m.active_item = 2; break; }
    }

    while(1)
    {
        menu_clear_enabled(&m);
        gfx_get_resolution(&res);
        switch(res.width)
        {
            case 640:  { m.items[0].enabled = 1; break; }
            case 1280: { m.items[1].enabled = 1; break; }
            case 1920: { m.items[2].enabled = 1; break; }
        }
        // Check user input
        MenuAction action = menu_input_tick(&m);

        // Act if prompted
        if(action == MENU_ACTION_ENTER)
        {
            switch(m.active_item)
            {
                case 0:
                {
                    res.width = 640;
                    res.height = 360;
                    gfx_set_resolution(res);
                    break;
                }
                case 1:
                {
                    res.width = 1280;
                    res.height = 720;
                    gfx_set_resolution(res);
                    break;
                }
                case 2:
                {
                    res.width = 1920;
                    res.height = 1080;
                    gfx_set_resolution(res);
                    break;
                }
                case 3 : goto end;
            }
        }
        else if(action == MENU_ACTION_RETURN) { goto end; }

        // Render everything
        gfx_scene_begin();
        menu_draw_all();
        gfx_scene_end();
    }

    end:
    menu_draw_unregister(&m);

    return;
}

void menu_options_multisampling(void)
{
    Menu m;
    const char *captions[] = {"None", "2x", "4x", "8x", "16x", "Back", 0} ;
    menu_initialize(&m, captions);
    m.x = MENU_DEFAULT_WIDTH*2 + MENU_DEFAULT_X*3;
    menu_draw_register(&m);

    // Get current multisampling
    GFX_Resolution res;
    gfx_get_resolution(&res);
    switch(res.multisampling)
    {
        default: { m.active_item = 0; break; }
        case 2:  { m.active_item = 1; break; }
        case 4:  { m.active_item = 2; break; }
        case 8:  { m.active_item = 3; break; }
        case 16: { m.active_item = 4; break; }
    }

    while(1)
    {
        menu_clear_enabled(&m);
        gfx_get_resolution(&res);
        switch(res.multisampling)
        {
            default: { m.items[0].enabled = 1; break; }
            case 2:  { m.items[1].enabled = 1; break; }
            case 4:  { m.items[2].enabled = 1; break; }
            case 8:  { m.items[3].enabled = 1; break; }
            case 16: { m.items[4].enabled = 1; break; }
        }

        // Check user input
        MenuAction action = menu_input_tick(&m);

        // Act if prompted
        if(action == MENU_ACTION_ENTER)
        {
            switch(m.active_item)
            {
                case 0:
                {
                    res.multisampling = 0;
                    gfx_set_resolution(res);
                    break;
                }
                case 1:
                {
                    res.multisampling = 2;
                    gfx_set_resolution(res);
                    break;
                }
                case 2:
                {
                    res.multisampling = 4;
                    gfx_set_resolution(res);
                    break;
                }
                case 3:
                {
                    res.multisampling = 8;
                    gfx_set_resolution(res);
                    break;
                }
                case 4:
                {
                    res.multisampling = 16;
                    gfx_set_resolution(res);
                    break;
                }
                case 5: goto end;
            }
        }
        else if(action == MENU_ACTION_RETURN) { goto end; }

        // Render everything
        gfx_scene_begin();
        menu_draw_all();
        gfx_scene_end();
    }

    end:
    menu_draw_unregister(&m);

    return;
}

void menu_options_sound(void)
{
    Menu m;
    const char *captions[] = {"On", "Off", "Back", 0} ;
    menu_initialize(&m, captions);
    m.x = MENU_DEFAULT_WIDTH*2 + MENU_DEFAULT_X*3;
    menu_draw_register(&m);

    // Get current sound state
    int sound_state;
    sfx_get_sound_state(&sound_state);
    if(sound_state) { m.active_item = 0; }
    else            { m.active_item = 1; }

    while(1)
    {
        sfx_get_sound_state(&sound_state);
        menu_clear_enabled(&m);
        m.items[1-sound_state].enabled = 1;

        // Check user input
        MenuAction action = menu_input_tick(&m);

        // Act if prompted
        if(action == MENU_ACTION_ENTER)
        {
            switch(m.active_item)
            {
                case 0:
                {
                    sfx_set_sound_state(1);
                    sfx_sound_play(SFX_SOUND_MENU_ENTER);
                    break;
                }
                case 1: { sfx_set_sound_state(0); break; }
                case 2 : goto end;
            }
        }
        else if(action == MENU_ACTION_RETURN) { goto end; }

        // Render everything
        gfx_scene_begin();
        menu_draw_all();
        gfx_scene_end();
    }

    end:
    menu_draw_unregister(&m);

    return;
}

void menu_highscores(void)
{
    Menu m;
    const char *captions[] = {"Reset", "Back", 0} ;
    menu_initialize(&m, captions);
    m.active_item = 1;
    m.x = MENU_DEFAULT_WIDTH + MENU_DEFAULT_X*2;
    menu_draw_register(&m);

    while(1)
    {
        // Check user input
        MenuAction action = menu_input_tick(&m);

        // Act if prompted
        if(action == MENU_ACTION_ENTER)
        {
            switch(m.active_item)
            {
                case 0: { io_highscore_reset(); break; }
                case 1: goto end;
            }
        }
        else if(action == MENU_ACTION_RETURN) { goto end; }

        // Render everything
        gfx_scene_begin();
        menu_draw_all();

        // Draw scores
        mat3 mat;
        vec2 translate = {MENU_DEFAULT_X+300, MENU_DEFAULT_Y};
        mat3_identity(mat);
        mat3_translate(mat, translate);
        gfx_matrix_push(mat);

        gfx_draw_set_color(GFX_BLACK);
        gfx_draw_rectangle(-4, -4, MENU_DEFAULT_WIDTH+4, 16*12 + 4);
        gfx_draw_set_color(GFX_WHITE);
        vec2 border[2] = {{-4, -4,}, {MENU_DEFAULT_WIDTH+4, 16*12 + 4 }};
        gfx_draw_line(border[0][0], border[0][1], border[1][0], border[0][1]);
        gfx_draw_line(border[1][0], border[0][1], border[1][0], border[1][1]);
        gfx_draw_line(border[1][0], border[1][1], border[0][0], border[1][1]);
        gfx_draw_line(border[0][0], border[1][1], border[0][0], border[0][0]);

        gfx_draw_text(0, 0, "Highscores");
        gfx_draw_text(0, 16, "-------------");
        for(int i = 0; i < 10; i++)
        {
            Highscore score;
            io_highscore_read(&score, i);
            char text[80];
            sprintf(text, "%s  %8d", score.name, score.score);
            gfx_draw_text(0, 16*(i+2), text);
        }
        gfx_matrix_pop();

        gfx_scene_end();
    }

    end:
    menu_draw_unregister(&m);

    return;
}

void menu_draw_virtual_background(void)
{
    const vec2 scale = {1.1, 1.1} ;
    vec2 off;
    off[0] = (sin(time_get()/3) - 1) * 640 * (scale[0] - 1) / 2;
    off[1] = (cos(time_get())   - 1) * 360 * (scale[1] - 1) / 2;

    mat3 m;
    mat3_identity(m);
    mat3_scale(m, (float*)scale);
    mat3_translate(m, off);
    gfx_matrix_push(m);

    gfx_draw_set_color(GFX_GREEN);
    const int nb_segs = 16;
    for(int i = 0; i < nb_segs; i++)
    {
        vec2 l1[2], l2[2];
        vec2 dumb = {1, 1};
        l1[0][0] = (float)(i) / (nb_segs-1);
        l1[0][1] = 0;
        l1[1][0] = 0;
        l1[1][1] = 1-(float)(i) / (nb_segs-1);
        vec2_sub(l2[0], dumb, l1[0]);
        vec2_sub(l2[1], dumb, l1[1]);
        gfx_draw_line(l1[0][0]*640, l1[0][1]*360, l1[1][0]*640, l1[1][1]*360);
        gfx_draw_line(l2[0][0]*640, l2[0][1]*360, l2[1][0]*640, l2[1][1]*360);
    }
    gfx_matrix_pop();
}

void menu_clear_enabled(Menu *menu)
{
    for(int i = 0; i < MENU_ITEMS_MAX; i++)
    {
        menu->items[i].enabled = 0;
    }
}
